Skip to content

fix(mail): refresh threads when any mailbox count changes - #381

Open
s-aga-r wants to merge 1 commit into
frappe:developfrom
s-aga-r:fix/mail-poll-thread-refresh
Open

fix(mail): refresh threads when any mailbox count changes#381
s-aga-r wants to merge 1 commit into
frappe:developfrom
s-aga-r:fix/mail-poll-thread-refresh

Conversation

@s-aga-r

@s-aga-r s-aga-r commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Fixes #171

Problem

The 30-second poll in MailboxView.vue gated the thread-list refresh on total_threads alone. A reply arriving into an existing thread changes only unread_threads/total_emails — so the sidebar badge updated (from get_mailboxes) while get_threads was never invoked and the list went stale. Read-state changes from another device/session hit the same gap.

Changes

  • get_mailboxes now also serializes total_emails and unread_emails (already stored on the Mailbox doctype from JMAP's totalEmails/unreadEmails) — these change for any new message, including a read reply into a read thread, which no thread-level count can catch.
  • pollForChanges compares a composite key of all four counts instead of total_threads alone.
  • Refresh merge (onResetSuccess): already-loaded threads now take their fresh row (new snippet, unread state, timestamp) in place instead of being discarded by the prepend-only merge — without this, the refetch triggered by the poll fix would fetch the updated row and then throw it away. Rows keep their position (no re-sort), so the list doesn't jump under the reader. This also benefits the existing socket-driven refresh path, which had the same blind spot.

Verification

  • All 24 mail frontend tests pass; production Vite build compiles cleanly.
  • Selections/keyboard focus are unaffected by the in-place row swap — they track thread_id strings and row keys, not object identity.

Known residual limitation: changes between two polls that net out to identical counts (e.g. one arrival + one deletion in the same 30s window) still won't trigger a refresh; catching that would need a JMAP state-token comparison, which is a larger change.

🤖 Generated with Claude Code

The 30s poll gated the thread-list refresh on total_threads alone, so a
reply landing in an existing thread (which moves only unread_threads /
total_emails) updated the sidebar badge without ever invoking
get_threads, leaving the list stale.

- serialize total_emails/unread_emails in get_mailboxes (the Mailbox
  doctype already stores them) and compare all four counts in the poll
- update already-loaded threads in place during a refresh merge so the
  refetched row (new snippet, unread state, timestamp) is actually
  shown instead of being discarded by the prepend-only merge

Fixes frappe#171
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mail(UI): get_threads is not called when mailboxes count changes

2 participants